package aoi

import (
	// "fmt"
)

// aoi 管理器接口声明
type AOI interface {
	Enter(int, int, int)
	Leave(int)
	Move(int, int, int)
}

// 网格 aoi 对象
type AOIGridEntity struct {
	id 		int
	x 		int	
	y		int	
	w 		int	 	// 视野宽度的一半，以网格坐为单位
	h 		int	 	// 视野高度的一半，以网格作为单位
	area 	int	 	// 当前所在区域
	last 	int	 	// 上一次所在区域

	status	int	 	// 状态 0 静止，1 移动，2 进入

	views 	map[int]*AOIGridEntity 	// 视野内的其它对象列表
	addviews []int
	delviews []int

	areas 	map[int]int 	 	// 视野内的区域列表
	addareas []int
	delareas []int

}


func NewAOIGridEntity(id int, x int, y int, w int, h int) *AOIGridEntity {
	e := &AOIGridEntity{}
	e.id = id
	e.x = x
	e.y = y
	e.w = w
	e.h = h
	e.area = -1
	e.last = -1
	e.status = 2

	e.views = make(map[int]*AOIGridEntity)
	e.areas = make(map[int]int)

	return e
}

// 网格 aoi 区域
type AOIGridArea struct {
	entitys []*AOIGridEntity 	
	adds []*AOIGridEntity 	
	dels []*AOIGridEntity 	
}

func (a *AOIGridArea) Add(e *AOIGridEntity) {
	for _, v := range a.entitys {
		if v == e {
			return
		}
	}
	a.entitys = append(a.entitys, e)
	a.adds = append(a.adds, e)
}

func (a *AOIGridArea) Remove(e *AOIGridEntity) {
	for k, v := range a.entitys {
		if v == e {
			a.entitys = append(a.entitys[:k], a.entitys[k+1:]...)
			a.dels = append(a.dels, e)
			break
		}
	}
}

// 网硌 aoi 管理器
type AOIGridManager struct {
	entitys map[int]*AOIGridEntity 	
	areas []*AOIGridArea 	
	mapWidth int 	
	mapHeight int 	
	w int 	
	h int 	
	s int 	 	// 每个网格大小

	viewWidth int 		 // 实体的水平视野的一半
	viewHeight int 	 	 // 实体的垂直视野的一半

	EvtFunc	func(string, int, []int) 	// 事件响应函数
}

func NewAOIGridManager(mapWidth int, mapHeight int, s int, viewWidth int, viewHeight int) *AOIGridManager {
	mgr := &AOIGridManager{}
	mgr.entitys = make(map[int]*AOIGridEntity)
	mgr.mapWidth = mapWidth
	mgr.mapHeight = mapHeight
	mgr.s = s
	mgr.w = mgr.mapWidth / s + 1
	if 0 == mgr.mapWidth % s {
		mgr.w--
	}
	mgr.h = mgr.mapHeight / s + 1
	if 0 == mgr.mapHeight % s {
		mgr.h--
	}
	count := mgr.w * mgr.h
	mgr.areas = make([]*AOIGridArea, 0, count + 1)
	for i := 0; i <= count; i++ {
		mgr.areas = append(mgr.areas, &AOIGridArea{})
	}
	mgr.viewWidth = viewWidth
	mgr.viewHeight = viewHeight
	return mgr
}

func (mgr *AOIGridManager) Enter(id int, x int, y int) {
	if _, ok := mgr.entitys[id]; ok {
		mgr.Move(id, x, y)
	} else {
		if x < 0 {
			x = 0
		} else if x > mgr.mapWidth {
			x = mgr.mapWidth
		}
		if y < 0 {
			y = 0
		} else if y > mgr.mapHeight {
			y = mgr.mapHeight
		}
		e := NewAOIGridEntity(id, x, y, mgr.viewWidth, mgr.viewHeight)
		mgr.entitys[e.id] = e
	}
}

func (mgr *AOIGridManager) Leave(id int) {
	if e, ok := mgr.entitys[id]; ok {
		delete(mgr.entitys, id)
		mgr.areas[e.area].Remove(e)
		e.area = -1
		e.Clear()
	}
}

func (mgr *AOIGridManager) Move(id int, x int, y int) {
	if e, ok := mgr.entitys[id]; ok {
		if x < 0 {
			x = 0
		} else if x > mgr.mapWidth {
			x = mgr.mapWidth
		}
		if y < 0 {
			y = 0
		} else if y > mgr.mapHeight {
			y = mgr.mapHeight
		}
		if e.x != x || e.y != y {
			e.x = x
			e.y = y
			e.status = 1
		}
	}
}

// 向 toId 发送 ids 列表的事件更新信息
func (mgr *AOIGridManager) OnEvent(evt string, toId int, ids []int) {
	// fmt.Println(evt, toId, ids)
	if nil != mgr.EvtFunc {
		mgr.EvtFunc(evt, toId, ids)
	}
}

func (mgr *AOIGridManager) Update() {
	for _, e := range mgr.entitys {
		if e.status != 0 {
			mgr.CheckEntity(e)
		}
	}
	moves := make([]int, 0)
	for _, e := range mgr.entitys {
		if e.status != 0 {
			mgr.CheckViews(e)
		}
	}
	for _, e := range mgr.entitys {
		if len(e.addviews) > 0 {
			ids := make([]int, len(e.addviews))
			copy(ids, e.addviews)
			e.addviews = e.addviews[:0]
			mgr.OnEvent("enter", e.id, ids)
		}
		for _, v := range e.views {
			if 1 == v.status {
				moves = append(moves, v.id)
			}
		}
		if len(moves) > 0 {
			ids := make([]int, len(moves))
			copy(ids, moves)
			moves = moves[:0]
			mgr.OnEvent("move", e.id, ids)
		}
		if len(e.delviews) > 0 {
			ids := make([]int, len(e.delviews))
			copy(ids, e.delviews)
			e.delviews = e.delviews[:0]
			mgr.OnEvent("leave", e.id, ids)
		}

		e.status = 0
	}

	for _, g := range mgr.areas {
		if len(g.adds) > 0 {
			g.adds = g.adds[:0]
		}
		if len(g.dels) > 0 {
			g.dels = g.dels[:0]
		}
	}
}

// 检查移动实体的 aoi 
func (mgr *AOIGridManager) CheckEntity(e *AOIGridEntity) {
	r := e.x / mgr.s
	c := e.y / mgr.s
	if e.x > 0 && e.x % mgr.s == 0 {
		r--
	}
	if e.y > 0 && e.y % mgr.s == 0 {
		c--
	}
	a := c * mgr.w + r
	if a != e.area {
		if e.area >= 0 {
			mgr.areas[e.area].Remove(e)
		}
		e.last = e.area
		e.area = a
		mgr.areas[e.area].Add(e)

		adds := make(map[int]int, 0)
		for i := r - e.w; i <= r + e.w; i++ {
			if i >= 0 && i < mgr.w {
				for j := c - e.h; j <= c + e.h; j++ {
					if j >= 0 && j < mgr.h {
						a = j * mgr.w + i
						if _, ok := e.areas[a]; !ok {
							e.areas[a] = 0
							e.addareas = append(e.addareas, a)
						}
						adds[a] = 0
					}
				}
			}
		}
		for k, _ := range e.areas {
			if _, ok := adds[k]; !ok {
				delete(e.areas, k)
				e.delareas = append(e.delareas, k)
			}
		}
	}
}

func (mgr *AOIGridManager) CheckViews(e *AOIGridEntity) {
	for k, _ := range e.areas {
		g := mgr.areas[k]
		if len(g.adds) > 0 {
			for _, e1 := range g.adds {
				if e1 != e {
					e.Add(e1)
				}
			}
		}
		if len(g.dels) > 0 {
			for _, e1 := range g.dels {
				if e1 != e {
					if _, ok := e.areas[e1.area]; !ok {
						e.Remove(e1)
					}
				}
			}
		}
	}
	if len(e.addareas) > 0 {
		for _, v := range e.addareas {
			g := mgr.areas[v]
			for _, e1 := range g.entitys {
				if e1 != e {
					e.Add(e1)
				}
			}
		}
		e.addareas = e.addareas[:0]
	}
	if len(e.delareas) > 0 {
		for _, v := range e.delareas {
			g := mgr.areas[v]
			for _, e1 := range g.entitys {
				if e1 != e {
					e.Remove(e1)
				}
			}
		}
		e.delareas = e.delareas[:0]
	}
}

func (mgr *AOIGridManager) GetArea(x int, y int) int {
	r := x / mgr.s
	c := y / mgr.s
	if x > 0 && x % mgr.s == 0 {
		r--
	}
	if y > 0 && y % mgr.s == 0 {
		c--
	}
	return c * mgr.w + r
}

// 获取在实体视野内的玩家列表
func (mgr *AOIGridManager) GetViews(id int) []int {
	var rets []int
	if e, ok := mgr.entitys[id]; ok {
		rets = make([]int, 0, len(e.views))
		for k, _ := range e.views {
			rets = append(rets, k)
		}
	}
	return rets
}

func (e *AOIGridEntity) Add(e1 *AOIGridEntity) {
	if _, ok := e.views[e1.id]; !ok {
		e.views[e1.id] = e1
		e.addviews = append(e.addviews, e1.id)

		e1.views[e.id] = e
		e1.addviews = append(e1.addviews, e.id)
	}
}

func (e *AOIGridEntity) Remove(e1 *AOIGridEntity) {
	if _, ok := e.views[e1.id]; ok {
		delete(e.views, e1.id)
		e.delviews = append(e.delviews, e1.id)

		delete(e1.views, e.id)
		e1.delviews = append(e1.delviews, e.id)
	}
}

func (e *AOIGridEntity) Clear() {
	for k, e1 := range e.views {
		delete(e.views, k)

		delete(e1.views, e.id)
		e1.delviews = append(e1.delviews, e.id)
	}
}